# 新闻蓝图的视图模块
from flask import abort
from flask import current_app, jsonify
from flask import g
from flask import render_template
from flask import request
from flask import session

from info import db
from info.models import News, User, Comment, CommentLike
from info.utils.common import user_login_data
from info.utils.response_code import RET
from . import news_blue

# 关注/取消关注该作者后端逻辑
# 请求路径: /news/followed_user
# 请求方式: POST
# 请求参数:user_id,action
# 返回值: errno, errmsg
@news_blue.route('/followed_user', methods=['POST'])
@user_login_data
def followed_user():
    """
    # 判断用户是否登陆
    1.接收获取参数：author_id,action操作类型
    2.校验参数，为空校验
    3.查询作者是否存在
    4.判断操作类型是否正确
    5.判断执行关注/取消关注操作
    6.返回状态
    :return:
    """
    # 判断用户是否登陆
    if not g.user:
        return jsonify(errno=RET.NODATA,errmsg='用户未登录')
    # 1.接收获取参数：author_id,action操作类型
    author_id = request.json.get('user_id')
    action = request.json.get('action')
    # 2.校验参数，为空校验
    if not all([author_id,action]):
        return jsonify(errno=RET.PARAMERR,errmsg='参数不全')
    # 3.判断操作类型是否正确
    if not action in ['follow', 'unfollow']:
        return jsonify(errno=RET.DATAERR, errmsg='操作类型异常')

    # 4.查询作者是否存在
    try:
        author = User.query.get(author_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="数据库查询失败")
    if not author:
        return jsonify(errno=RET.NODATA,errmsg='该作者不存在')

    # 5.判断执行关注/取消关注操作
    if action == 'follow':
        if not g.user in author.followers:
            author.followers.append(g.user)
    else:
        if g.user in author.followers:
            author.followers.remove(g.user)
    # 6.返回状态
    return jsonify(errno=RET.OK,errmsg='操作成功')



#点赞/取消点赞
# 请求路径: /news/comment_like
# 请求方式: POST
# 请求参数:news_id[可选],comment_id,action,g.user
# 返回值: errno,errmsg
@news_blue.route('/news_comment_like',methods=['post'])
@user_login_data
def news_comment_like():
    """
    思路分析：
    1.判断用户是否登陆
    2.接受参数
    参数：comment_id,g.user,操作类型action
    3.为空校验
    4.判断这个评论对象是否存在
    5.操作类型action类型
    6.创建评论对象，执行操作
    7.返回数据，（状态，数据）
    :return:
    """
    # 1.判断用户是否登陆
    if not g.user:
        return jsonify(errno=RET.NODATA,errmsg='该用户未登录')
    # 2.接受参数
    # 参数：comment_id,g.user,操作类型action
    comment_id = request.json.get('comment_id')
    action = request.json.get('action')
    # 3.为空校验
    if not all([comment_id,action]):
        return jsonify(errno=RET.PARAMERR,errmsg='参数不全')
    # 4.判断这个评论对象是否存在
    try:
       comment =Comment.query.get(comment_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="数据库查询错误")
    if not comment:
        return jsonify(errno=RET.NODATA, errmsg="该评论不存在")
    # 5.操作类型action类型
    if not action in (['add','remove']):
        return jsonify(errno=RET.PARAMERR, errmsg="操作类型有误  ")
    # 6.创建评论对象，执行操作
    try:
        if action == 'add':
            commentlike = CommentLike.query.filter(CommentLike.comment_id == comment_id,
                                                   CommentLike.user_id == g.user.id).first()
            if not commentlike:
                commentlike = CommentLike()
                commentlike.user_id = g.user.id
                commentlike.comment_id = comment_id
                # 将当前评论的点赞数量+1
                comment.like_count += 1
                # 提交
                db.session.add(commentlike)
                db.session.commit()
        else:
            commentlike = CommentLike.query.filter(CommentLike.comment_id == comment_id,
                                                   CommentLike.user_id == g.user.id).first()
            if commentlike:
                db.session.delete(commentlike)
                # 将当前评论的点赞数量-1
                comment.like_count -= 1
                # 提交
                db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="数据库操作失败")

    # 6.返回数据，（状态，数据）
    return jsonify(errno=RET.OK,errmsg="操作成功")


# 添加评论功能
@news_blue.route('/news_comment',methods=['post'])
@user_login_data
def news_comment():
    """
    思路分析：
    1.判断用户是否登录
    2.接受参数
    参数：new_id,g.user,comment,parent
    3.校验参数，为空校验，
    4.新闻对象是否存在校验
    5.创建评论对象，存到数据库
    6.返回数据（状态，数据）
    :return:
    """
    # 1.判断用户是否登录
    if not g.user:
        return jsonify(errno=RET.NODATA,errmsg="该用户未登录")
    # 2.接受参数
    # 参数：news_id,g.user,comment,parent_id
    news_id = request.json.get('news_id')
    content = request.json.get('content')
    parent_id = request.json.get('parent_id')
    # 3.校验参数，为空校验，
    if not all([news_id,content]):
        return jsonify(errno=RET.PARAMERR,errmsg="参数不全")
    # 4.新闻对象是否存在校验
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="数据库查询失败")
    if not news:
        return jsonify(errno=RET.NODATA,errmsg="该新闻不存在")
    # 5.创建评论对象，存到数据库
    comment =Comment()
    comment.user_id = g.user.id
    comment.news_id = news_id
    comment.content= content
    if parent_id:
        comment.parent_id = parent_id
    # 新创建的数据需要提交，数据库的配置只能更新更改的数据，不能更新创建新对象这种操作
    try:
        db.session.add(comment)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR,errmsg="添加评论失败")
    # 6.返回数据（状态，数据）
    return jsonify(errno=RET.OK,errmsg="操作成功",data=comment.to_dict())


#收藏/取消收藏
# 请求路径: /news/news_collect
# 请求方式: POST
# 请求参数:news_id,action, g.user
# 返回值: errno,errmsg
@news_blue.route('/news_collect',methods=['post'])
@user_login_data
def news_collect():
    """
    思路分析：
    1.用户是否登陆判断
    2.接受参数
    参数：news_id,g.user,操作类型(collect,cancle_collect)
    3.校验参数，为空判断，collect类型判断
    4.根据news_id查询新闻是否存在
    5.根据操作类型进行取消或收藏
    6.返回状态
    :return:
    """
    # 1.用户是否登陆判断
    if not g.user:
        return jsonify(errno=RET.NODATA,errmsg="该用户未登录")
    # 2.接受参数
    # 参数：news_id,g.user,操作类型(collect,cancle_collect)
    news_id = request.json.get('news_id')
    action = request.json.get('action')
    # 3.校验参数，为空判断，collect类型判断
    if not all([news_id,action]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不全")

    if not action  in ['collect','cancle_collect']:
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    # 4.根据news_id查询新闻是否存在
    try:
       news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="数据库查询失败")
    if not news :
        return jsonify(errno=RET.NODATA, errmsg="该新闻不存在")
    # 5.根据操作类型进行取消或收藏
    try:
        if action == 'collect':
            g.user.collection_news.append(news)
        else:
            g.user.collection_news.remove(news)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="操作失败")
    # 6.返回数据（状态，数据）
    return jsonify(errno=RET.OK, errmsg="操作成功")




@news_blue.route('/<int:news_id>')
@user_login_data
def news_details(news_id):
    """
    1.根据news_id查询数据库
    2.查询数据返回
    返回数据为details页面和数据
    :param news_id:
    :return:
    """
    # 查询是否有用户登陆，返回用户登陆信息
    # user_id = session.get('user_id')
    # user = None
    # if user_id:
    #     try:
    #         user = User.query.get(user_id)
    #     except Exception as e:
    #         current_app.logger.erro(e)

    try:
        news=News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="查询数据库失败")

    # 判断新闻是否存在,同意做404处理
    if not news:
        abort(404)
    # 将新闻点击量+1,因为执行了这一步，用户肯定点击了这条新闻
    news.clicks +=1

    # 处理热门新闻，查询前8条
    # 获取排行数据
    new_list = None
    try:
        new_list = News.query.order_by(News.clicks.desc()).limit(8).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询新闻失败")
    click_new_list = []
    for items in new_list if new_list else []:
        click_new_list.append(items.to_dict())

    # 查看用户是否收藏该新闻
    is_collect = False
    # 如果用户登录并且该新闻在用户的收藏列表中，说明该新闻收藏过
    if g.user and news in g.user.collection_news:
        is_collect = True

    # 查询该新闻的所有评论列表内容返回
    try:
         comments = Comment.query.filter(Comment.news_id == news.id).order_by(Comment.create_time.desc()).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="数据库查询错误")

    # comments_list=[]
    # for comment in comments:
    #     comments_list.append(comment.to_dict())
    # 取出该评论的编号
    comment_ids = [comm.id for comm in comments]

    # 查询该新闻该用户所有点赞的评论返回数据渲染页面
    try:
       comment_like_list = CommentLike.query.filter(CommentLike.comment_id.in_(comment_ids),CommentLike.user_id==g.user.id).all()
       my_comment_like_ids=[comment_like.comment_id for comment_like in comment_like_list]
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="数据库查询错误")

    # 将评论列表内容转成字典
    comments_list = []
    for comment in comments:
        comment_dict = comment.to_dict()
        comment_dict['is_like'] =False
        if g.user and comment.id in my_comment_like_ids:
            comment_dict['is_like'] = True

        comments_list.append(comment_dict)
    # 判断用户是否关注过该新闻作者
    is_followed = False
    # 用户需要登陆，并且新闻要有作者
    if g.user and news.user:
        # 用户需要在新闻作者的粉丝列表中
       if g.user in news.user.followers:
            is_followed = True

    data={
        'user_info':g.user.to_dict() if g.user else '',
        'news':news.to_dict(),
        'click_new_list':click_new_list,
        'is_collect': is_collect,
        'comments_list':comments_list,
        'is_followed': is_followed

    }

    return render_template('news/detail.html',data=data)



